<?php defined('MINICAKE') or exit('can not access!');

/**
 * Dispatcher 
 * 解释uri,并运行相应的控制器
 * @package 
 * @version $id$
 * @copyright 
 * @author lovise <lovise.lu@gmail.com> 
 * @license PHP Version 3.0 {@link http://www.php.net/license/3_0.txt}
 */
class Dispatcher extends Object {
	/**
	 * default_controller 
	 * 缺省控制器情况下使用的控制器
	 * @var string
	 * @access public
	 */
	var $default_controller = 'index';
	/**
	 * default_action 
	 * 缺省动作情况下使用的动作
	 * @var string
	 * @access public
	 */
	var $default_action = 'index';
	/**
	 * autoRender 
	 * 是否自动渲染
	 * @var mixed
	 * @access public
	 */
	var $autoRender = true;
	/**
	 * uri 
	 * 
	 * @var string
	 * @access public
	 */
	var $uri = '';
	/**
	 * uri_segmentation 
	 * 路径分隔符
	 * @var string
	 * @access public
	 */
	var $uri_segmentation = '/';
	/**
	 * uri_argvs 
	 * 
	 * @var array
	 * @access public
	 */
	var $uri_argvs = array();
	/**
	 * controller 
	 * 
	 * @var string
	 * @access public
	 */
	var $controller = '';
	/**
	 * action 
	 * 
	 * @var string
	 * @access public
	 */
	var $action = '';
	/**
	 * route 
	 * 通过route.php配置的路由表
	 * @var string
	 * @access public
	 */
	var $route = array();
	/**
	 * route_controllers 
	 * 路由表中需路由的控制器
	 * @var array
	 * @access public
	 */
	var $route_controllers = array();
	
	/**
	 * __construct 
	 * 
	 * @param mixed $uri 
	 * @access public
	 * @return void
	 */
	function __construct($uri){
		$this->uri_segmentation = Configure::getItem('uri_segmentation');
		$this->default_controller = Configure::getItem('default_controller');
		$this->default_action = Configure::getItem('default_action');
		Configure::load('route');
		$this->route = Configure::getItems('route');
		$this->_setRouteControllers();
		$this->uri = $uri;
		$this->_parseUri();
		$this->_dispatcher();
	}

	function _dispatcher(){
		if(file_exists(APP.'controllers'.DS.$this->controller.'.php')){
			include_once(APP.'controllers'.DS.$this->controller.'.php');
			$controllerClassName = $this->controller.'Controller';
			if(class_exists($controllerClassName)){
				$app = new $controllerClassName();
				if(method_exists($app,$this->action)){
					$app->beforeAction();
					call_user_func_array(array($app,$this->action),array_slice($this->uri_argvs,2));
				}else{
					throw new Exception("Dispatcher::_dispatcher(): controller {$controllerClassName} does not contain the action {$this->action}");
				}
				$output = $app->render($this->action);
				if(($this->autoRender === true) && ($app->autoRender === true)){
					echo $output;
				}
				return $output;
			}else{
				throw new Exception("Dispatcher::_dispatcher(): class {$controllerClassName} not exist");
			}
		}else{
			throw new Exception("Dispatcher::_dispatcher():  {$this->controller}.php not exist");
		}
	}
	function _parseUri(){
		//处理一下uri前后的 '/'
		if((substr($this->uri,-1) === '/')){
			if($this->uri !== '/'){
				$this->uri = substr($this->uri,1,-1);
			}
		}else{
			$this->uri = substr($this->uri,1);
		}
		if($this->uri === '/'){
				//为根目录的时候
				$this->uri_argvs[0] = $this->controller = $this->default_controller;
				$this->uri_argvs[1] = $this->action = $this->default_action;
		}else{
			$temp_uri = explode($this->uri_segmentation,$this->uri);
			if(empty($this->route) or !in_array($temp_uri[0],$this->route_controllers)){
				//如果没有设置route，将会是/controller/action/argvs/的顺序
				if(count($temp_uri)== 1){
					//如果只有controller的时候
					$this->uri_argvs[0] = $this->controller = $temp_uri[0];
					$this->uri_argvs[1] = $this->action = $this->default_action;
				}else{
					$this->uri_argvs = & $temp_uri;
					$this->controller = $temp_uri[0];
					$this->action = $temp_uri[1];
				}
			}else{
				//如果设置了路由，这里进行路由的匹配
				foreach ($this->route as $key => $val) {
					$key = str_replace(':any','.+',$key);
					$key = str_replace(':num','[0-9]+',$key);
					
					if(preg_match('#^'.$key.'$#',$this->uri)){
						$val = preg_replace('#^'.$key.'$#',$val,$this->uri);
						$temp_uri = explode($this->uri_segmentation,$val);
						$this->uri_argvs = & $temp_uri;
						$this->controller = $temp_uri[0];
						$this->action = $temp_uri[1];
						return true;
					}
				}
			}
			unset($temp_uri);
		}
	}

	/**
	 * _setRouteControllers 
	 * 
	 * @access public
	 * @return void
	 */
	function _setRouteControllers(){
		if(is_array($this->route)){
			foreach ($this->route as $key => $val){
				if(strpos($key,$uri_segmentation)){
					$temp = explode($uri_segmentation,$key);
					$this->routeControllers[] = $temp[0];
					unset($temp);
				}else{
					$this->routeControllers[] = $key;
				}
			}
		}
	}
}
?>
